home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 25 / CU Amiga Magazine's Super CD-ROM 25 (1998)(EMAP Images)(GB)(Track 1 of 2)[!][issue 1998-08].iso / CUCD / Programming / QuakeTools / src / libqtools / map.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-06-11  |  22.1 KB  |  947 lines

  1. #define    LIBQTOOLS_CORE
  2. #include "../include/libqtools.h"
  3. #include "../include/libqbuild.h"
  4.  
  5. char token[MAXTOKEN];                                   // 128
  6. bool unget;                                       // ?
  7. char *script_p;                                       // 4
  8. int scriptline;                                       // 4
  9. struct entity *mapent;                               // 4
  10. int nummapbrushes;                               // 4
  11. short int numlighttargets;
  12. char lighttargets[32][64];
  13.  
  14. vec3_t baseaxis[18] =                               // 216
  15.  {
  16.    {0, 0, 1},
  17.    {1, 0, 0},
  18.    {0, -1, 0},                                       // floor
  19.     {0, 0, -1},
  20.    {1, 0, 0},
  21.    {0, -1, 0},                                       // ceiling
  22.     {1, 0, 0},
  23.    {0, 1, 0},
  24.    {0, 0, -1},                                       // west wall
  25.     {-1, 0, 0},
  26.    {0, 1, 0},
  27.    {0, 0, -1},                                       // east wall
  28.     {0, 1, 0},
  29.    {1, 0, 0},
  30.    {0, 0, -1},                                       // south wall
  31.     {0, -1, 0},
  32.    {1, 0, 0},
  33.    {0, 0, -1}                                       // north wall
  34. };
  35.  
  36. //============================================================================
  37.  
  38. /*
  39.  * ===============
  40.  * FindMiptex
  41.  * 
  42.  * ===============
  43.  */
  44. int FindMiptex(__memBase, char *name)
  45. {
  46.   int i;
  47.  
  48.   for (i = 0; i < bspMem->nummaptexstrings; i++) {
  49.     if (!strcmp(name, bspMem->maptexstrings[i]))
  50.       return i;
  51.   }
  52.   if (bspMem->nummaptexstrings == bspMem->max_nummaptexstrings)
  53.     ExpandClusters(bspMem, MAP_TEXSTRINGS);
  54.   strncpy(bspMem->maptexstrings[i], name, 16);
  55.   bspMem->nummaptexstrings++;
  56.   return i;
  57. }
  58.  
  59. /*
  60.  * ===============
  61.  * FindTexinfo
  62.  * 
  63.  * Returns a global texinfo number
  64.  * ===============
  65.  */
  66. int FindTexinfo(__memBase, struct texinfo *t)
  67. {
  68.   int i, j;
  69.   struct texinfo *tex;
  70.  
  71. // set the special flag
  72.   if (bspMem->maptexstrings[t->miptex][0] == '*' || !strncasecmp(bspMem->maptexstrings[t->miptex], "sky", 3))
  73.     t->flags |= TEX_SPECIAL;
  74.  
  75.   tex = bspMem->texinfo;
  76.   for (i = 0; i < bspMem->numtexinfo; i++, tex++) {
  77.     if (t->miptex != tex->miptex)
  78.       continue;
  79.     if (t->flags != tex->flags)
  80.       continue;
  81.  
  82.     for (j = 0; j < 8; j++)
  83.       if (t->vecs[0][j] != tex->vecs[0][j])
  84.     break;
  85.     if (j != 8)
  86.       continue;
  87.  
  88.     return i;
  89.   }
  90.  
  91. // allocate a new texture
  92.   if (bspMem->numtexinfo == bspMem->max_numtexinfo)
  93.     ExpandClusters(bspMem, LUMP_TEXINFO);
  94.   bspMem->texinfo[i] = *t;
  95.   bspMem->numtexinfo++;
  96.  
  97.   return i;
  98. }
  99.  
  100. //JIM
  101. struct entity *FindEntityWithKeyPair(__memBase, char *key, char *value)
  102. {
  103.   struct entity *ent;
  104.   struct epair *ep;
  105.   int i;
  106.  
  107.   //for(i = 0, ent = bspMem->mapentities; i < bspMem->nummapentities; i++, ent++) {
  108.   for (i = 0; i < bspMem->nummapentities; i++) {
  109.     ent = &bspMem->mapentities[i];
  110.     for (ep = ent->epairs; ep; ep = ep->next) {
  111.       if (!strcmp(ep->key, key)) {
  112.     if (!strcmp(ep->value, value)) {
  113.       return ent;
  114.     }
  115.     break;
  116.       }
  117.     }
  118.   }
  119.   return NULL;
  120. }
  121.  
  122. struct entity *FindTargetEntity(__memBase, char *target)
  123. {
  124.   int i;
  125.  
  126.   for (i = 0; i < bspMem->nummapentities; i++)
  127.     if (!strcmp(bspMem->mapentities[i].targetname, target))
  128.       return &bspMem->mapentities[i];
  129.  
  130.   return NULL;
  131. }
  132.  
  133. struct entity *FindEntityWithModel(__memBase, int modnum)
  134. {
  135.   int i;
  136.   char *s;
  137.   char name[16];
  138.  
  139.   sprintf(name, "*%i", modnum);
  140.   // search the entities for one using modnum
  141.   for (i = 0; i < bspMem->nummapentities; i++) {
  142.     s = ValueForKey(&bspMem->mapentities[i], "model");
  143.     if (!strcmp(s, name))
  144.       return &bspMem->mapentities[i];
  145.   }
  146.  
  147.   return &bspMem->mapentities[0];
  148. }
  149.  
  150. //============================================================================
  151.  
  152. void StartTokenParsing(char *data)
  153. {
  154.   scriptline = 1;
  155.   script_p = data;
  156.   unget = FALSE;
  157. }
  158.  
  159. bool GetToken(bool crossline)
  160. {
  161.   char *token_p;
  162.  
  163.   if (unget)                                       // is a token allready waiting?
  164.  
  165.     return TRUE;
  166.  
  167. //
  168.   // skip space
  169.   //
  170. skipspace:
  171.   while (*script_p <= 32) {
  172.     if (!*script_p) {
  173.       if (!crossline)
  174.     Error("Line %i is incomplete", scriptline);
  175.       return FALSE;
  176.     }
  177.     if (*script_p++ == '\n') {
  178.       if (!crossline)
  179.     Error("Line %i is incomplete", scriptline);
  180.       scriptline++;
  181.     }
  182.   }
  183.  
  184.   if (script_p[0] == '/' && script_p[1] == '/')                       // comment field
  185.    {
  186.     if (!crossline)
  187.       Error("Line %i is incomplete\n", scriptline);
  188.     while (*script_p++ != '\n')
  189.       if (!*script_p) {
  190.     if (!crossline)
  191.       Error("Line %i is incomplete", scriptline);
  192.     return FALSE;
  193.       }
  194.     goto skipspace;
  195.   }
  196.  
  197. //
  198.   // copy token
  199.   //
  200.   token_p = token;
  201.  
  202.   if (*script_p == '"') {
  203.     script_p++;
  204.     while (*script_p != '"') {
  205.       if (!*script_p)
  206.     Error("EOF inside quoted token");
  207.       *token_p++ = *script_p++;
  208.       if (token_p > &token[MAXTOKEN - 1])
  209.     Error("Token too large on line %i", scriptline);
  210.     }
  211.     script_p++;
  212.   }
  213.   else
  214.     while (*script_p > 32) {
  215.       *token_p++ = *script_p++;
  216.       if (token_p > &token[MAXTOKEN - 1])
  217.     Error("Token too large on line %i", scriptline);
  218.     }
  219.  
  220.   *token_p = 0;
  221.  
  222.   return TRUE;
  223. }
  224.  
  225. void UngetToken(void)
  226. {
  227.   unget = TRUE;
  228. }
  229.  
  230. //============================================================================
  231.  
  232. /*
  233.  * =================
  234.  * ParseEpair
  235.  * =================
  236.  */
  237. void ParseEpair(void)
  238. {
  239.   struct epair *e;
  240.  
  241.   if (!(e = (struct epair *)tmalloc(sizeof(struct epair))))
  242.       Error("ParseEpair: failed to allocate epair!\n");
  243.  
  244.   e->next = mapent->epairs;
  245.   mapent->epairs = e;
  246.  
  247.   if (strlen(token) >= MAX_KEY - 1)
  248.     Error("ParseEpar: token too long");
  249.   if (!(e->key = smalloc(token)))
  250.     Error("ParseEpair: failed to allocate key!\n");
  251.   GetToken(FALSE);
  252.   if (strlen(token) >= MAX_VALUE - 1)
  253.     Error("ParseEpar: token too long");
  254.   if (!(e->value = smalloc(token)))
  255.     Error("ParseEpair: failed to allocate value!\n");
  256. }
  257.  
  258. //============================================================================
  259.  
  260. /*
  261.  * ==================
  262.  * textureAxisFromPlane
  263.  * ==================
  264.  */
  265. void TextureAxisFromPlane(struct plane *pln, vec3_t xv, vec3_t yv)
  266. {
  267.   short int bestaxis;
  268.   float dot, best;
  269.   short int i;
  270.  
  271.   best = 0;
  272.   bestaxis = 0;
  273.  
  274.   for (i = 0; i < 6; i++) {
  275.     dot = DotProduct(pln->normal, baseaxis[i * 3]);
  276.     if (dot > best) {
  277.       best = dot;
  278.       bestaxis = i;
  279.     }
  280.   }
  281.  
  282.   VectorCopy(baseaxis[bestaxis * 3 + 1], xv);
  283.   VectorCopy(baseaxis[bestaxis * 3 + 2], yv);
  284. }
  285.  
  286. //=============================================================================
  287.  
  288. void GetEdges(__memBase, register int ledge, register struct dedge_t *edge)
  289. {
  290.   if (bspMem->dsurfedges[ledge] > 0) {
  291.     *edge = bspMem->dedges[bspMem->dsurfedges[ledge]];
  292.   }
  293.   else {
  294.     edge->v[0] = bspMem->dedges[-(bspMem->dsurfedges[ledge])].v[1];
  295.     edge->v[1] = bspMem->dedges[-(bspMem->dsurfedges[ledge])].v[0];
  296.   }
  297. }
  298.  
  299. struct mface *AddFace(register struct mbrush *b, register int t, register vec3_t planepts0, register vec3_t planepts1, register vec3_t planepts2)
  300. {
  301.   struct mface *f;
  302.   vec3_t t1, t2, t3;
  303.   short int j;
  304.  
  305.   if (!(f = (struct mface *)tmalloc(sizeof(struct mface))))
  306.     Error("AddFace: failed to allocate mface!\n");
  307.  
  308.   // convert to a vector / dist plane
  309.   for (j = 0; j < 3; j++) {
  310.     t1[j] = planepts0[j] - planepts1[j];
  311.     t2[j] = planepts2[j] - planepts1[j];
  312.     t3[j] = planepts1[j];
  313.   }
  314.  
  315.   CrossProduct(t1, t2, f->plane.normal);
  316.   if (VectorZero(f->plane.normal)) {
  317.     eprintf("brush plane with no normal\n");
  318.     tfree(f);
  319.     f = 0;
  320.   }
  321.   else {
  322.     f->next = b->faces;
  323.     b->faces = f;
  324.  
  325.     VectorNormalize(f->plane.normal);
  326.     f->plane.dist = DotProduct(t3, f->plane.normal);
  327.     f->texinfo = t;
  328.     VectorCopy(planepts0, f->p0);
  329.     VectorCopy(planepts1, f->p1);
  330.     VectorCopy(planepts2, f->p2);
  331.   }
  332.   
  333.   return f;
  334. }
  335.  
  336. void ParseFace(__memBase, register struct entity *bspent, register int face)
  337. {
  338.   short int numfaceedges;
  339.   short int firstfaceedge;
  340.   int ledge, ledge2;
  341.   struct dedge_t edges[MAXEDGES];
  342.   struct dvertex_t vert_beg[MAXEDGES];
  343.   struct dvertex_t vert_end[MAXEDGES];
  344.   vec3_t normal, v1, v2, v3;
  345.   int t = bspMem->dfaces[face].texinfo;
  346.   struct mbrush *b;
  347.  
  348.   if (!(b = (struct mbrush *)tmalloc(sizeof(struct mbrush))))
  349.       Error("ProessFace: failed to allocate mbrush!\n");
  350.  
  351.   nummapbrushes++;
  352.   b->next = bspent->brushes;
  353.   bspent->brushes = b;
  354.  
  355.   numfaceedges = bspMem->dfaces[face].numedges;
  356.   firstfaceedge = bspMem->dfaces[face].firstedge;
  357.  
  358.   if (numfaceedges < 3)
  359.     Error("too few edges for face");
  360.  
  361.   if (numfaceedges > MAXEDGES)
  362.     Error("too many edges for face");
  363.  
  364.   for (ledge2 = ledge = 0; ledge < numfaceedges; ledge++, ledge2++) {
  365.     GetEdges(bspMem, ledge2 + firstfaceedge, &edges[ledge]);
  366.     vert_beg[ledge] = bspMem->dvertexes[edges[ledge].v[0]];
  367.     vert_end[ledge] = bspMem->dvertexes[edges[ledge].v[1]];
  368.  
  369.     if (VectorCompare(vert_beg[ledge].point, vert_end[ledge].point))
  370.       ledge--;
  371.   }
  372.  
  373.   VectorCopy(bspMem->dplanes[bspMem->dfaces[face].planenum].normal, normal);
  374.   VectorScale(normal, (float)2, normal);
  375.  
  376.   if (!bspMem->dfaces[face].side)
  377.     VectorInverse(normal);
  378.  
  379.   for (ledge2 = 1; ledge2 < numfaceedges - 2; ledge2++) {
  380.     VectorSubtract(vert_end[0].point, vert_beg[0].point, v1);
  381.     VectorSubtract(vert_end[ledge2].point, vert_beg[ledge2].point, v2);
  382.     VectorNormalize(v1);
  383.     VectorNormalize(v2);
  384.  
  385.     if (!VectorCompare(v1, v2))
  386.       break;
  387.   }
  388.  
  389.   AddFace(b, t, vert_beg[0].point, vert_end[0].point, vert_end[ledge2].point);
  390.  
  391.   for (ledge = 0; ledge < numfaceedges; ledge++) {
  392.     if (ledge == 0) {
  393.       VectorSubtract(vert_end[numfaceedges - 1].point, vert_beg[numfaceedges - 1].point, v1);
  394.       VectorSubtract(vert_end[ledge].point, vert_beg[ledge].point, v2);
  395.       VectorNormalize(v1);
  396.       VectorNormalize(v2);
  397.       if (VectorCompare(v1, v2))
  398.     continue;
  399.     }
  400.     else {
  401.       VectorSubtract(vert_end[ledge - 1].point, vert_beg[ledge - 1].point, v1);
  402.       VectorSubtract(vert_end[ledge].point, vert_beg[ledge].point, v2);
  403.       VectorNormalize(v1);
  404.       VectorNormalize(v2);
  405.       if (VectorCompare(v1, v2))
  406.     continue;
  407.     }
  408.  
  409.     VectorAdd(vert_end[ledge].point, normal, v2);
  410.     AddFace(b, t, vert_end[ledge].point, vert_beg[ledge].point, v2);
  411.   }
  412.  
  413.   VectorAdd(vert_beg[0].point, normal, v2);
  414.   VectorAdd(vert_end[0].point, normal, v1);
  415.   VectorAdd(vert_end[ledge2].point, normal, v3);
  416.   AddFace(b, t, v1, v2, v3);
  417. }
  418.  
  419. //=============================================================================
  420.  
  421. /*
  422.  * fake proper texture vectors from QuakeEd style
  423.  */
  424. int MakeTexinfo (__memBase, char *texname, struct mface *f, float *scale, float rotate, float *shift) {
  425.   struct texinfo tx;
  426.   vec3_t vecs[2];
  427.   int sv, tv;
  428.   float ang, sinv, cosv;
  429.   float ns, nt;
  430.   short int i, j;
  431.  
  432.   memset(&tx, 0, sizeof(tx));
  433.   tx.miptex = FindMiptex(bspMem, texname);
  434.   tfree(texname);
  435.  
  436.   TextureAxisFromPlane(&f->plane, vecs[0], vecs[1]);
  437.  
  438.   if (!scale[0])
  439.     scale[0] = 1;
  440.   if (!scale[1])
  441.     scale[1] = 1;
  442.  
  443.   // rotate axis
  444.   if (rotate == 0) {
  445.     sinv = 0;
  446.     cosv = 1;
  447.   }
  448.   else if (rotate == 90) {
  449.     sinv = 1;
  450.     cosv = 0;
  451.   }
  452.   else if (rotate == 180) {
  453.     sinv = 0;
  454.     cosv = -1;
  455.   }
  456.   else if (rotate == 270) {
  457.     sinv = -1;
  458.     cosv = 0;
  459.   }
  460.   else {
  461.     ang = rotate / 180 * Q_PI;
  462.     sinv = sin(ang);
  463.     cosv = cos(ang);
  464.   }
  465.  
  466.   if (vecs[0][0])
  467.     sv = 0;
  468.   else if (vecs[0][1])
  469.     sv = 1;
  470.   else
  471.     sv = 2;
  472.  
  473.   if (vecs[1][0])
  474.     tv = 0;
  475.   else if (vecs[1][1])
  476.     tv = 1;
  477.   else
  478.     tv = 2;
  479.  
  480.   for (i = 0; i < 2; i++) {
  481.     ns = cosv * vecs[i][sv] - sinv * vecs[i][tv];
  482.     nt = sinv * vecs[i][sv] + cosv * vecs[i][tv];
  483.     vecs[i][sv] = ns;
  484.     vecs[i][tv] = nt;
  485.   }
  486.  
  487.   for (i = 0; i < 2; i++)
  488.     for (j = 0; j < 3; j++)
  489.       tx.vecs[i][j] = vecs[i][j] / scale[i];
  490.  
  491.   tx.vecs[0][3] = shift[0];
  492.   tx.vecs[1][3] = shift[1];
  493.  
  494.   // unique the texinfo
  495.   return FindTexinfo(bspMem, &tx);
  496. }
  497.  
  498. /*
  499.  * =================
  500.  * ParseBrush
  501.  * =================
  502.  */
  503. void ParseBrush(__memBase)
  504. {
  505.   struct mbrush *b;
  506.   struct mface *f, *f2;
  507.   vec3_t planepts[3];
  508.   short int i, j;
  509.   vec_t d;
  510.   float shift[2], rotate, scale[2];
  511.   char *texname;
  512.  
  513.   if (!(b = (struct mbrush *)tmalloc(sizeof(struct mbrush))))
  514.       Error("ParseBrush: failed to allocate mbrush!\n");
  515.  
  516.   nummapbrushes++;
  517.   b->next = mapent->brushes;
  518.   mapent->brushes = b;
  519.   
  520.   do {
  521.     if (!GetToken(TRUE))
  522.       break;
  523.     if (!strcmp(token, "}"))
  524.       break;
  525.  
  526.     // read the three point plane definition
  527.     for (i = 0; i < 3; i++) {
  528.       if (i != 0)
  529.     GetToken(TRUE);
  530.       if (strcmp(token, "("))
  531.     Error("parsing brush");
  532.  
  533.       for (j = 0; j < 3; j++) {
  534.     GetToken(FALSE);
  535.     planepts[i][j] = atof(token);
  536.       }
  537.  
  538.       GetToken(FALSE);
  539.       if (strcmp(token, ")"))
  540.     Error("parsing brush");
  541.  
  542.     }
  543.  
  544.     // read the texturedef
  545.     GetToken(FALSE);
  546.     texname = smalloc(token);
  547.     GetToken(FALSE);
  548.     shift[0] = atof(token);
  549.     GetToken(FALSE);
  550.     shift[1] = atof(token);
  551.     GetToken(FALSE);
  552.     rotate = atof(token);
  553.     GetToken(FALSE);
  554.     scale[0] = atof(token);
  555.     GetToken(FALSE);
  556.     scale[1] = atof(token);
  557.  
  558.     // if the three points are all on a previous plane, it is a
  559.     // duplicate plane
  560.     for (f2 = b->faces; f2; f2 = f2->next) {
  561.       for (i = 0; i < 3; i++) {
  562.     d = DotProduct(planepts[i], f2->plane.normal) - f2->plane.dist;
  563.     if (d < -ON_EPSILON || d > ON_EPSILON)
  564.       break;
  565.       }
  566.       if (i == 3)
  567.     break;
  568.     }
  569.     if (f2) {
  570.       eprintf("brush with duplicate plane\n");
  571.       continue;
  572.     }
  573.     
  574.     if((f = AddFace(b, 0, planepts[0], planepts[1], planepts[2])))
  575.       f->texinfo = MakeTexinfo(bspMem, texname, f, scale, rotate, shift);
  576.   } while (1);
  577. }
  578.  
  579. /*
  580.  * ================
  581.  * ParseEntity
  582.  * ================
  583.  */
  584. bool ParseEntity(__memBase)
  585. {
  586.   if (!GetToken(TRUE))
  587.     return FALSE;
  588.  
  589.   if (strcmp(token, "{"))
  590.     Error("ParseEntity: { not found");
  591.  
  592.   if (bspMem->nummapentities == bspMem->max_nummapentities)
  593.     ExpandClusters(bspMem, MAP_ENTITIES);
  594.   mapent = &bspMem->mapentities[bspMem->nummapentities];
  595.   bspMem->nummapentities++;
  596.  
  597.   do {
  598.     if (!GetToken(TRUE))
  599.       Error("ParseEntity: EOF without closing brace");
  600.     if (!strcmp(token, "}"))
  601.       break;
  602.     if (!strcmp(token, "{"))
  603.       ParseBrush(bspMem);
  604.     else
  605.       ParseEpair();
  606.   } while (1);
  607.  
  608.   /*
  609.    * for all 
  610.    */
  611.   GetVectorForKey(mapent, "origin", mapent->origin);
  612.   mapent->classname = ValueForKey(mapent, "classname");
  613.   mapent->target = ValueForKey(mapent, "target");
  614.   mapent->targetname = ValueForKey(mapent, "targetname");
  615.  
  616.   /*
  617.    * special for qbsp+light+vis in one part 
  618.    */
  619.   if (bspMem->mapOptions & MAP_LOADLIGHTS) {
  620.     if (!(mapent->light = FloatForKeyN(mapent, "light")))
  621.       if (!(mapent->light = FloatForKey(mapent, "_light")))
  622.     mapent->light = 0;
  623.     if (!(mapent->style = FloatForKey(mapent, "style")))
  624.       if (!(mapent->style = FloatForKey(mapent, "_style")))
  625.     mapent->style = 0;
  626.     mapent->angle = FloatForKey(mapent, "angle");
  627.  
  628.     if (!strncmp(mapent->classname, "light", 5)) {
  629.       if (!mapent->light)
  630.     mapent->light = DEFAULTLIGHTLEVEL;
  631.  
  632.       //if (!mapent->classname[5])) {
  633.         if (mapent->targetname[0] && !mapent->style) {
  634.       char s[256];
  635.  
  636.       mapent->style = LightStyleForTargetname(mapent->targetname, TRUE);
  637.       sprintf(s, "%i", mapent->style);
  638.       SetKeyValue(mapent, "style", s);
  639.     }
  640.       //}
  641.     }
  642.   }
  643.   return TRUE;
  644. }
  645.  
  646. /*
  647.  * ================
  648.  * LoadMapFile
  649.  * ================
  650.  */
  651. bool LoadMapFile(__memBase, char *mapBuf)
  652. {
  653.   StartTokenParsing(mapBuf);
  654.   bspMem->nummapentities = 0;
  655.  
  656.   mprintf("----- LoadMapFile -------\n");
  657.  
  658.   while (ParseEntity(bspMem)) {
  659.   }
  660.   MatchTargets(bspMem);
  661.  
  662.   if(nummapbrushes)
  663.     mprintf("%5i brushes\n", nummapbrushes);
  664.   if(bspMem->nummapentities)
  665.     mprintf("%5i entities\n", bspMem->nummapentities);
  666.   if(bspMem->nummaptexstrings)
  667.     mprintf("%5i miptex\n", bspMem->nummaptexstrings);
  668.   if(bspMem->numtexinfo)
  669.     mprintf("%5i texinfo\n", bspMem->numtexinfo);
  670.  
  671.   return TRUE;
  672. }
  673.  
  674. /*
  675.  * ================
  676.  * SaveMapFile
  677.  * ================
  678.  */
  679. bool SaveMapFile(__memBase, FILE *outFile)
  680. {
  681.   struct entity *ent;
  682.   struct epair *ep;
  683.   struct mbrush *b;
  684.   struct mface *f;
  685.   int i;
  686.   struct dmiptexlump_t *head_miptex = (struct dmiptexlump_t *)bspMem->dtexdata;
  687.   struct texinfo *texinfo;
  688.   struct mipmap *miptex;
  689.  
  690.   mprintf("----- SaveMapFile -------\n");
  691.  
  692.   for (i = 0, ent = bspMem->mapentities; i < bspMem->nummapentities; i++, ent++) {
  693.     fprintf(outFile, "{\n");
  694.  
  695.     for (ep = ent->epairs; ep; ep = ep->next)
  696.       if (strcmp(ep->key, "model"))
  697.     fprintf(outFile, "  \"%s\" \"%s\"\n", ep->key, ep->value);
  698.  
  699.     for (b = ent->brushes; b; b = b->next) {
  700.       fprintf(outFile, "  {\n");
  701.  
  702.       for (f = b->faces; f; f = f->next) {
  703.         texinfo = &bspMem->texinfo[f->texinfo];
  704.         miptex = (struct mipmap *)((((unsigned char *)bspMem->dtexdata)) + (head_miptex->dataofs[texinfo->miptex]));
  705.         
  706.     //here must calc x_off y_off rotation x_scale y_scale from p_texinfo->vecs !
  707.     fprintf(outFile, "    ( %g %g %g ) ( %g %g %g ) ( %g %g %g ) %s %g %g %g %g %g\n",
  708.         f->p0[0], f->p0[1], f->p0[2], f->p1[0], f->p1[1], f->p1[2], f->p2[0], f->p2[1], f->p2[2], miptex->name, texinfo->vecs[0][3], texinfo->vecs[1][3], 0.0, 1.0, 1.0);
  709.       }
  710.  
  711.       fprintf(outFile, "  }\n");
  712.     }
  713.  
  714.     fprintf(outFile, "}\n");
  715.     mprogress(bspMem->nummapentities, i + 1);
  716.   }
  717.  
  718.   return TRUE;
  719. }
  720.  
  721. /*
  722.  * ================
  723.  * LoadBSPFile
  724.  * ================
  725.  */
  726. bool LoadBSPFile(__memBase)
  727. {
  728.   struct entity *ent;
  729.   struct epair *ep;
  730.   int face;
  731.   int i;
  732.  
  733.   mprintf("----- LoadBSPFile -------\n");
  734.  
  735.   for (i = 0, ent = bspMem->mapentities; i < bspMem->nummapentities; i++, ent++) {
  736.     int modelfaces = 0;
  737.     int numfaces = 0;
  738.  
  739.     for (ep = ent->epairs; ep; ep = ep->next) {
  740.       if (!strcmp(ep->key, "model")) {
  741.     int model = atoi(ep->value);
  742.  
  743.     numfaces = bspMem->dmodels[model].numfaces;
  744.     modelfaces = bspMem->dmodels[model].firstface;
  745.       }
  746.  
  747.       if (!strcmp(ep->key, "classname") && !strcmp(ep->value, "worldspawn")) {
  748.     numfaces = bspMem->dmodels[0].numfaces;
  749.     modelfaces = bspMem->dmodels[0].firstface;
  750.       }
  751.     }
  752.     if (numfaces)
  753.       for (face = 0; face < numfaces; face++, modelfaces++)
  754.     ParseFace(bspMem, ent, modelfaces);
  755.     mprogress(bspMem->nummapentities, i + 1);
  756.   }
  757.  
  758.   mprintf("%5i brushes\n", nummapbrushes);
  759.  
  760.   return TRUE;
  761. }
  762.  
  763. /*
  764.  * ==============================================================================
  765.  * 
  766.  * ENTITY FILE PARSING
  767.  * 
  768.  * If a light has a targetname, generate a unique style in the 32-63 range
  769.  * ==============================================================================
  770.  */
  771.  
  772. int LightStyleForTargetname(char *targetname, bool alloc)
  773. {
  774.   int i;
  775.  
  776.   for (i = 0; i < numlighttargets; i++)
  777.     if (!strcmp(lighttargets[i], targetname))
  778.       return 32 + i;
  779.   if (!alloc)
  780.     return -1;
  781.   strcpy(lighttargets[i], targetname);
  782.   numlighttargets++;
  783.   return numlighttargets - 1 + 32;
  784. }
  785.  
  786. /*
  787.  * ==================
  788.  * MatchTargets
  789.  * ==================
  790.  */
  791. void MatchTargets(__memBase)
  792. {
  793.   int i;
  794.  
  795.   for (i = 0; i < bspMem->nummapentities; i++) {
  796.     if (bspMem->mapentities[i].target[0]) {
  797.       if (!(bspMem->mapentities[i].targetent = FindTargetEntity(bspMem, bspMem->mapentities[i].target)))
  798.         eprintf("entity at (%i,%i,%i) (%s) has unmatched target\n", (int)bspMem->mapentities[i].origin[0], (int)bspMem->mapentities[i].origin[1], (int)bspMem->mapentities[i].origin[2], bspMem->mapentities[i].classname);
  799.       else {
  800.         // set the style on the source ent for switchable lights
  801.         if (bspMem->mapentities[i].targetent->style) {
  802.       char s[256];
  803.  
  804.       bspMem->mapentities[i].style = bspMem->mapentities[i].targetent->style;
  805.       sprintf(s, "%i", bspMem->mapentities[i].style);
  806.       SetKeyValue(&bspMem->mapentities[i], "style", s);
  807.     }
  808.       }
  809.     }
  810.   }
  811. }
  812.  
  813. void WriteEntitiesToString(__memBase)
  814. {
  815.   char *buf, *end;
  816.   struct epair *ep;
  817.   char line[128];
  818.   int i;
  819.  
  820.   buf = bspMem->dentdata;
  821.   end = bspMem->dentdata + bspMem->max_entdatasize - SAVE_BACK;
  822.   *buf = 0;
  823.  
  824.   for (i = 0; i < bspMem->nummapentities; i++) {
  825.     ep = bspMem->mapentities[i].epairs;
  826.     if (!ep)
  827.       continue;                                       // ent got removed
  828.  
  829.     strcat(buf, "{\n");
  830.     buf += 2;
  831.  
  832.     /*
  833.      * if free at this use "ep = FreeEpair(ep)" 
  834.      */
  835.     for (ep = bspMem->mapentities[i].epairs; ep; ep = ep->next) {
  836.       sprintf(line, "\"%s\" \"%s\"\n", ep->key, ep->value);
  837.       
  838.       if ((buf + strlen(line)) >= end) {
  839.         int len = buf - bspMem->dentdata;
  840.  
  841.         ExpandClusters(bspMem, LUMP_ENTITIES);
  842.         end = bspMem->dentdata + bspMem->max_entdatasize - SAVE_BACK;
  843.         buf = bspMem->dentdata + len;
  844.       }
  845.       
  846.       strcat(buf, line);
  847.       buf += strlen(line);
  848.     }
  849.     strcat(buf, "}\n");
  850.     buf += 2;
  851.   }
  852.   bspMem->entdatasize = buf - bspMem->dentdata + 1;
  853. }
  854.  
  855. void PrintEntity(struct entity *ent)
  856. {
  857.   struct epair *ep;
  858.  
  859.   for (ep = ent->epairs; ep; ep = ep->next)
  860.     mprintf("%20s : %s\n", ep->key, ep->value);
  861.   mprintf("-------------------- - --------------------\n");
  862.   mprintf("%20s : %s\n", "classname", ent->classname);
  863.   mprintf("%20s : %g\n", "angle", ent->angle);
  864.   mprintf("%20s : ( %g %g %g )\n", "origin", ent->origin[0], ent->origin[1], ent->origin[2]);
  865.   mprintf("%20s : %d\n", "light", ent->light);
  866.   mprintf("%20s : %d\n", "style", ent->style);
  867.   mprintf("%20s : %s\n", "target", ent->target);
  868.   mprintf("%20s : %s\n", "targetname", ent->targetname);
  869. }
  870.  
  871. char *ValueForKey(struct entity *ent, char *key)
  872. {
  873.   struct epair *ep;
  874.  
  875.   for (ep = ent->epairs; ep; ep = ep->next)
  876.     if (!strcmp(ep->key, key))
  877.       return ep->value;
  878.   return "";
  879. }
  880.  
  881. char *ValueForKeyN(struct entity *ent, char *key)
  882. {
  883.   struct epair *ep;
  884.   int len = strlen(key);
  885.  
  886.   for (ep = ent->epairs; ep; ep = ep->next)
  887.     if (!strncmp(ep->key, key, len))
  888.       return ep->value;
  889.   return "";
  890. }
  891.  
  892. void SetKeyValue(struct entity *ent, char *key, char *value)
  893. {
  894.   struct epair *ep;
  895.  
  896.   for (ep = ent->epairs; ep; ep = ep->next)
  897.     if (!strcmp(ep->key, key)) {
  898.       tfree(ep->value);
  899.       ep->value = smalloc(value);
  900.       return;
  901.     }
  902.   if (!(ep = (struct epair *)tmalloc(sizeof(*ep))))
  903.     Error("SetKeyValue: failed to allocate epair!\n");
  904.   ep->next = ent->epairs;
  905.   ent->epairs = ep;
  906.   if (!(ep->key = smalloc(key)))
  907.     Error("SetKeyValue: failed to allocate key!\n");
  908.   if (!(ep->value = smalloc(value)))
  909.     Error("SetKeyValue: failed to allocate value!\n");
  910. }
  911.  
  912. float FloatForKey(struct entity *ent, char *key)
  913. {
  914.   char *k;
  915.   float ret = 0;
  916.  
  917.   if ((k = ValueForKey(ent, key)))
  918.     if(k[0])
  919.       ret = atof(k);
  920.  
  921.   return ret;
  922. }
  923.  
  924. float FloatForKeyN(struct entity *ent, char *key)
  925. {
  926.   char *k;
  927.   float ret = 0;
  928.  
  929.   if ((k = ValueForKeyN(ent, key)))
  930.     if(k[0])
  931.       ret = atof(k);
  932.  
  933.   return ret;
  934. }
  935.  
  936. void GetVectorForKey(struct entity *ent, char *key, vec3_t vec)
  937. {
  938.   char *k;
  939.  
  940.   vec[0] = vec[1] = vec[2] = 0;
  941.   // scanf into doubles, then assign, so it is vec_t size independent
  942.   if ((k = ValueForKey(ent, key)))
  943.     if (k[0])
  944.       if (sscanf(k, "%g %g %g", &vec[0], &vec[1], &vec[2]) != 3)
  945.     Error("GetVectorForKey: not 3 points as expected: %g %g %g (%s = %s)!\n", vec[0], vec[1], vec[2], key, k);
  946. }
  947.